package org.gongliang.jsmile.common.task;

import java.lang.reflect.Method;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.gongliang.jsmile.authc.task.entity.QrtzTask;
import org.gongliang.jsmile.common.constants.KConstant;
import org.gongliang.jsmile.common.enums.SF;
import org.gongliang.jsmile.common.kit.StrKit;
import org.gongliang.jsmile.common.kit.web.SpringKit;
import org.quartz.CronExpression;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;

/**
 * @description 定时任务工具类
 * @author 龚亮
 * @date 2015-05-27 14:22:13
 */
public class TaskKit {

	private static final Logger logger = LoggerFactory.getLogger(TaskKit.class);

	private static SchedulerFactoryBean schedulerFactoryBean = SpringKit.getBean(SchedulerFactoryBean.class);

	/**
	 * 获取所有已经存在的job
	 */
	public static List<QrtzTask> getAllJob() throws SchedulerException {
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
		Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
		List<QrtzTask> jobList = Lists.newArrayList();
		for (JobKey jobKey : jobKeys) {
			List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
			for (Trigger trigger : triggers) {
				QrtzTask job = new QrtzTask();
				job.setJobName(jobKey.getName());
				job.setJobGroup(jobKey.getGroup());
				Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
				job.setRemark("触发器:" + trigger.getKey() + ":状态" + triggerState.name());
				job.setTaskStatus(KConstant.TASK.STATUS_NORMAL);
				if (trigger instanceof CronTrigger) {
					CronTrigger cronTrigger = (CronTrigger) trigger;
					String cronExpression = cronTrigger.getCronExpression();
					job.setCron(cronExpression);
				}
				jobList.add(job);
			}
		}
		return jobList;
	}

	/**
	 * 判断某个job是否存在
	 * 
	 * @param jobName
	 *            任务名称
	 * @param jobGroup
	 *            任务组
	 */
	public static boolean existsJob(String jobName, String jobGroup) throws SchedulerException {
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
		return scheduler.checkExists(jobKey);
	}

	/**
	 * 判断某个job是否存在,存在就修改cron
	 * 
	 * @param jobName
	 *            任务名称
	 * @param jobGroup
	 *            任务组
	 * @throws ParseException
	 */
	public static void existsJobUpdateCron(QrtzTask task) throws SchedulerException, ParseException {
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		TriggerKey triggerKey = TriggerKey.triggerKey(task.getJobName(), task.getJobGroup());
		Trigger trigger = scheduler.getTrigger(triggerKey);
		CronTrigger cronTrigger = (CronTrigger) trigger;
		if (null == cronTrigger) {
			CronExpression exp = new CronExpression(task.getCron());
			Date nextTime = exp.getNextValidTimeAfter(new Date());
			if (nextTime != null) {
				TaskKit.addJob(task, null);
			}
		} else {
			String cronExpression = cronTrigger.getCronExpression();
			if (!StringUtils.equals(task.getCron(), cronExpression)) {
				TaskKit.updateJobCron(task);
			}
		}
	}

	/**
	 * 删除一个任务
	 */
	public static void deleteJob(QrtzTask task) throws SchedulerException {
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getJobGroup());
		scheduler.deleteJob(jobKey);
	}

	/**
	 * 暂停一个任务
	 */
	public static void pauseJob(QrtzTask task) throws SchedulerException {
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getJobGroup());
		scheduler.pauseJob(jobKey);
	}

	/**
	 * 恢复一个任务
	 */
	public static void resumeJob(QrtzTask task) throws SchedulerException {
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getJobGroup());
		scheduler.resumeJob(jobKey);
	}

	/**
	 * 立即执行任务
	 */
	public static void runAJobNow(QrtzTask task) throws SchedulerException {
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getJobGroup());
		scheduler.triggerJob(jobKey);
	}

	/**
	 * 更改任务cron表达式
	 */
	public static void updateJobCron(QrtzTask task) throws SchedulerException {
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		TriggerKey triggerKey = TriggerKey.triggerKey(task.getJobName(), task.getJobGroup());
		CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
		CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(task.getCron())
				.withMisfireHandlingInstructionDoNothing();
		trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
		scheduler.rescheduleJob(triggerKey, trigger);
	}

	/**
	 * 添加一个任务
	 */
	@SuppressWarnings("unchecked")
	public static void addJob(QrtzTask task, Map<String, Object> data) throws SchedulerException {
		Preconditions.checkNotNull(task.getJobName(), "任务名称不能为空!");
		Preconditions.checkNotNull(task.getJobGroup(), "任务所属组不能为空!");
		Preconditions.checkNotNull(task.getCron(), "cron表达式不能为空!");
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		if (task == null || SF.F.getValue().equals(task.getTaskStatus())) {
			logger.error("任务名称 = [" + task.getJobName() + ",任务=" + task.getBeanClass() + "." + "execute"
					+ "]---------------添加失败，请检查是否配置正确！！！");
			return;
		}
		TriggerKey triggerKey = TriggerKey.triggerKey(task.getJobName(), task.getJobGroup());

		CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

		// 不存在，创建一个
		if (null == trigger) {
			Class<?> clazz = SF.S.getValue().equals(task.getIsConcurrent())
					? QuartzJobFactoryDisallowConcurrentExecution.class : QuartzJobFactory.class;
			JobDetail jobDetail = JobBuilder.newJob((Class<? extends Job>) clazz)
					.withIdentity(task.getJobName(), task.getJobGroup()).build();
			jobDetail.getJobDataMap().put(KConstant.TASK.SCHEDULE_JOB, task);
			jobDetail.getJobDataMap().put(KConstant.TASK.JOB_DATA_MAP, data);
			CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(task.getCron());
			trigger = TriggerBuilder.newTrigger().withIdentity(task.getJobName(), task.getJobGroup())
					.withSchedule(scheduleBuilder).build();
			scheduler.scheduleJob(jobDetail, trigger);
		} else {
			// Trigger已存在，那么更新相应的定时设置
			CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(task.getCron());
			// 按新的cronExpression表达式重新构建trigger
			trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
			// 按新的trigger重新设置job执行
			scheduler.rescheduleJob(triggerKey, trigger);
		}
	}

	/**
	 * 通过反射调用scheduleJob中定义的方法
	 * 
	 * @param scheduleJob
	 */
	public static void invokMethod(QrtzTask schedule, Object... args) {
		Object object = null;
		Class<?> clazz = null;
		if (StrKit.notBlank(schedule.getBeanClass())) {
			try {
				clazz = Class.forName(schedule.getBeanClass());
				object = clazz.newInstance();
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
			}

		}
		if (object == null) {
			logger.error("任务名称 = [" + schedule.getJobName() + ",任务=" + schedule.getBeanClass() + "."
					+ "execute" + "]---------------未启动成功，请检查是否配置正确！！！");
			return;
		}
		clazz = object.getClass();
		Method method = null;
		try {
			method = clazz.getDeclaredMethod("execute", Map.class);
		} catch (NoSuchMethodException e) {
			logger.error("任务名称 = [" + schedule.getJobName() + ",任务=" + schedule.getBeanClass() + "."
					+ "execute" + "]---------------未启动成功，方法名设置错误！！！");
		} catch (SecurityException e) {
			logger.error(e.getMessage(), e);
		}
		if (method != null) {
			try {
				method.invoke(object, args);
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
			}
		}
		logger.debug("任务名称 = [" + schedule.getJobName() + ",任务=" + schedule.getBeanClass() + "."
				+ "execute" + "]----------启动成功");
	}
}
